import os
import subprocess
import shutil
import zipfile
import datetime
import re # 用于解析版本号

# --- 配置 ---
PROJECT_NAME = "vs2cmake"
OUTPUT_EXE_NAME = f"{PROJECT_NAME}.exe"
CARGO_TOML_PATH = "Cargo.toml" # Cargo.toml 文件路径
CARGO_TARGET_DIR = os.path.join("target", "release")
# FINAL_ZIP_NAME 将在获取版本号后定义

# 要包含在 ZIP 包中的其他文件和目录 (相对于脚本所在位置)
# 如果文件在子目录中，请确保路径正确，例如 "docs/manual.pdf"
FILES_TO_INCLUDE = [
    "USAGE.md",
    # "README.md",
    "build_cmake.py",
    # 如果有其他DLL或资源文件需要从 target/release 复制，也可以在这里指定
    # 例如：os.path.join(CARGO_TARGET_DIR, "some_library.dll")
    # 并确保在下面的 copy_files_to_temp_dir 中正确处理源路径
]

TEMP_PACKAGE_DIR = "_package_temp"
# --- End 配置 ---

def get_project_version():
    """从 Cargo.toml 文件中读取并返回项目版本号。"""
    try:
        with open(CARGO_TOML_PATH, 'r', encoding='utf-8') as f:
            for line in f:
                if line.strip().startswith("version"):
                    match = re.search(r'version\s*=\s*"([^"]+)"', line)
                    if match:
                        return match.group(1)
        print(f"Error: Could not find version in {CARGO_TOML_PATH}")
        exit(1)
    except FileNotFoundError:
        print(f"Error: {CARGO_TOML_PATH} not found.")
        exit(1)
    except Exception as e:
        print(f"Error reading version from {CARGO_TOML_PATH}: {e}")
        exit(1)

# 在定义其他可能依赖它的常量之前获取版本号
PROJECT_VERSION = get_project_version()
FINAL_ZIP_NAME = f"{PROJECT_NAME}_{PROJECT_VERSION}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.zip"

def run_command(command):
    """运行一个shell命令并打印输出，如果失败则退出。"""
    print(f"Running command: {' '.join(command)}")
    try:
        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, encoding='utf-8', errors='replace')
        for line in process.stdout:
            print(line, end='')
        process.wait()
        if process.returncode != 0:
            print(f"Error: Command '{' '.join(command)}' failed with exit code {process.returncode}")
            exit(1)
        print(f"Command '{' '.join(command)}' executed successfully.")
    except FileNotFoundError:
        print(f"Error: Command not found: {command[0]}. Is it in your PATH?")
        exit(1)
    except Exception as e:
        print(f"An unexpected error occurred while running command: {' '.join(command)}")
        print(f"Error details: {e}")
        exit(1)

def create_temp_dir():
    """创建临时打包目录，如果已存在则清空。"""
    if os.path.exists(TEMP_PACKAGE_DIR):
        print(f"Cleaning up existing temporary directory: {TEMP_PACKAGE_DIR}")
        shutil.rmtree(TEMP_PACKAGE_DIR)
    print(f"Creating temporary directory: {TEMP_PACKAGE_DIR}")
    os.makedirs(TEMP_PACKAGE_DIR)

def copy_files_to_temp_dir():
    """复制必要的文件到临时打包目录。"""
    print("Copying files to temporary directory...")

    # 1. 复制编译好的可执行文件
    exe_source_path = os.path.join(CARGO_TARGET_DIR, OUTPUT_EXE_NAME)
    exe_dest_path = os.path.join(TEMP_PACKAGE_DIR, OUTPUT_EXE_NAME)
    if os.path.exists(exe_source_path):
        print(f"Copying {exe_source_path} to {exe_dest_path}")
        shutil.copy2(exe_source_path, exe_dest_path)
    else:
        print(f"Error: Compiled executable not found at {exe_source_path}. Make sure cargo build was successful.")
        exit(1)

    # 2. 复制 FILES_TO_INCLUDE 中列出的其他文件
    for item_path in FILES_TO_INCLUDE:
        source_path = item_path # 这些文件是相对于脚本根目录的
        
        # 特殊处理需要从 CARGO_TARGET_DIR 复制的文件 (如果适用)
        # 这个例子里，我们假设 FILES_TO_INCLUDE 中的路径都是相对于项目根目录的
        # 如果你的文件在 target/release 下，你需要调整 source_path 的构建逻辑
        # 例如：
        # if item_path.startswith(CARGO_TARGET_DIR):
        #     source_path = item_path # 已经是绝对或相对 target 的路径
        # else:
        #     source_path = item_path # 相对于项目根目录

        base_name = os.path.basename(item_path)
        dest_path = os.path.join(TEMP_PACKAGE_DIR, base_name)

        if os.path.exists(source_path):
            if os.path.isfile(source_path):
                print(f"Copying file {source_path} to {dest_path}")
                shutil.copy2(source_path, dest_path)
            elif os.path.isdir(source_path):
                print(f"Copying directory {source_path} to {dest_path}")
                shutil.copytree(source_path, dest_path)
        else:
            print(f"Warning: File or directory not found and will not be included: {source_path}")

def create_zip_archive():
    """将临时目录的内容打包成ZIP文件。"""
    zip_file_path = os.path.abspath(FINAL_ZIP_NAME) # 确保 ZIP 文件在项目根目录创建
    print(f"Creating ZIP archive: {zip_file_path}")
    
    # 更改当前工作目录到临时目录，以避免在 ZIP 中包含 TEMP_PACKAGE_DIR 本身作为根文件夹
    original_cwd = os.getcwd()
    os.chdir(TEMP_PACKAGE_DIR)
    
    try:
        with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zf:
            for root, _, files in os.walk("."): # 从当前目录（即 TEMP_PACKAGE_DIR）开始遍历
                for file in files:
                    file_path = os.path.join(root, file)
                    archive_name = os.path.relpath(file_path, ".") # ZIP 内的相对路径
                    print(f"Adding to ZIP: {file_path} as {archive_name}")
                    zf.write(file_path, arcname=archive_name)
        print(f"Successfully created ZIP archive: {zip_file_path}")
    finally:
        os.chdir(original_cwd) # 恢复原始工作目录

def cleanup_temp_dir():
    """删除临时打包目录。"""
    if os.path.exists(TEMP_PACKAGE_DIR):
        print(f"Cleaning up temporary directory: {TEMP_PACKAGE_DIR}")
        shutil.rmtree(TEMP_PACKAGE_DIR)

def main():
    print("Starting Windows packaging process...")

    # 1. 编译 Rust 项目
    print("Building Rust project (release mode)...")
    run_command(["cargo", "build", "--release"])

    # 2. 创建临时目录
    create_temp_dir()

    # 3. 复制文件
    copy_files_to_temp_dir()

    # 4. 创建 ZIP 压缩包
    create_zip_archive()

    # 5. 清理临时目录
    cleanup_temp_dir()

    print(f"Packaging complete! Output: {FINAL_ZIP_NAME}")
    print("Done.")

if __name__ == "__main__":
    main() 